package com.manage.competition.shiro;

import com.manage.competition.common.Const;
import com.manage.competition.entity.Permission;
import com.manage.competition.entity.Role;
import com.manage.competition.entity.User;
import com.manage.competition.repository.PermissionRepository;
import com.manage.competition.repository.RoleRepository;
import com.manage.competition.repository.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;

/**
 * Create with IDEA
 *
 * @Author:Vantcy
 * @Date: Create in 16:30 2019/1/25
 * @Description: 普通的自定义realm
 */
@Slf4j
public class AuthRealm extends AuthorizingRealm{


    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RoleRepository roleRepository;

    @Autowired
    private PermissionRepository permissionRepository;

    /**
     * 此Realm只支持UsernamePasswordToken
     * @return
     */
    @Override
    public Class<?> getAuthenticationTokenClass() { return UsernamePasswordToken.class; }
    @Override
    public boolean supports(AuthenticationToken token) { return token instanceof UsernamePasswordToken; }

    @Override
    public String getName(){
        return "AuthRealm";
    }

    /**
     * 获取身份验证信息
     * Shiro中，最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
     *
     * @param authenticationToken 用户身份信息 token
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken){
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        log.info("———————————————————{} auth身份认证方法开始——————————————————————",token.getUsername());

        // 从数据库获取对应用户名密码的用户
        User user = userRepository.findByUsername(token.getUsername());
        if (user == null){
            throw new UnknownAccountException();
        }
        //是否激活
        if(user.getStatus().equals(Const.Status.DISABLE)){
            throw new DisabledAccountException();
        }
        //是否锁定
        if(user.getStatus().equals(Const.Status.ILLEGAL)) {
            throw new LockedAccountException();
        }
        if(user.getStatus().equals(Const.Status.ENABLE)){
            //盐值
            ByteSource credentialsSalt = ByteSource.Util.bytes(user.getUsername());
            return new SimpleAuthenticationInfo(user, user.getPassword(),
                    credentialsSalt, getName());
        }
        return null;
    }

    /**
     * 获取授权信息
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        User user = (User)principalCollection.getPrimaryPrincipal();
        log.info("——————————————————————{} auth权限认证开始———————————————————————",user.getUsername());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //因为addRoles和addStringPermissions方法需要的参数类型是Collection
        //所以先创建两个collection集合
        Collection<String> rolesCollection = new HashSet<String>();
        Collection<String> permissionsCollection = new HashSet<String>();
        //获取user的Role的List集合
        List<Role> roles = roleRepository.findAllByUserId(user.getId());
        for (Role role: roles) {
            //将每一个role的name装进collection集合
            rolesCollection.add(role.getRole());
            List<Permission> permissions = permissionRepository.findAllByRoleId(role.getId());
            for (Permission permission:
                    permissions) {
                //将每一个permission的name装进collection集合
                permissionsCollection.add(permission.getPerm());
            }
            //为用户授予权限
            info.addStringPermissions(permissionsCollection);
        }
        //为用户授予角色
        info.addRoles(rolesCollection);
        log.info("——————————————————————auth权限认证结果  角色{} 权限{}———————————————————————",rolesCollection,permissionsCollection);
        return info;
    }
}
